package log

///
// 超时库
///
import (
	"fmt"
	"sync"
	"time"

	library ".."
)

// Time 时间信息
type Time struct {
	ID         int   // 标识
	Lock       bool  // 锁
	Period     int64 // 超时
	PeriodMax  int64 // 最大超时
	TakeEffect bool  // 生效
	Value      *interface{}
	Callback   func(T *Time, limit bool) func()
}

// Timeout 超时类
type Timeout struct {
	Queue    map[int]*Time
	Callback func(T *Time, limit bool) func()
	lock     *sync.RWMutex
}

// Init 初始化
func (T *Timeout) Init() {
	// 初始化队列
	T.Queue = make(map[int]*Time)
	T.lock = new(sync.RWMutex)
	// 检测超时
	go func() {
		for {
			// 等待一个调度
			<-time.After(time.Millisecond * 20)
			// 循环超时队列
			T.lock.RLock() // 读
			for _, t := range T.Queue {
				if t.TakeEffect {
					// 记录超时时长
					t.Period -= 20 // 更新生命周期
					// 极限超时时间
					if t.Period < t.PeriodMax {
						// 直接调用超时函数
						go t.Callback(t, true)
					}
					// 判断是否已超时
					if !t.Lock {
						// 检测超时
						if t.Period < 0 {
							t.Lock = true // 设置超时
						}
					}
				}
			}
			T.lock.RUnlock()
		}
	}()
	// 默认处理
	if T.Callback == nil {
		T.Callback = func(T *Time, limit bool) func() {
			return func() {
				if T.Lock {
					fmt.Println(fmt.Sprintf("超时时长: %d/ns\n内存占用: %d \n调用栈信息:\n%s\n注册参数:%v\n", -T.Period, library.MemorySize(), library.CallTrace(1), T.Value))
				}
				T.TakeEffect = false
			}
		}
	}
}

// Detection 检测超时
func (T *Timeout) Detection(time int64, timeMax int64, value interface{}) func() {
	T.lock.Lock() // 写
	t := T.getTime(time, -timeMax)
	T.lock.Unlock()
	t.Value = &value
	// 返回操作
	return (*t).Callback(t, false)
}

// getTime 获得 Time 调度
func (T *Timeout) getTime(time int64, timeMax int64) *Time {
	// 返回空闲数据
	for _, t := range T.Queue {
		if !t.TakeEffect {
			t.Lock = false
			t.Period = time
			t.PeriodMax = timeMax
			t.TakeEffect = true
			return t
		}
	}
	// 添加新数据
	n := len(T.Queue) + 1
	T.Queue[n] = &Time{
		ID:         n, // 用来标识是那一个调度
		Lock:       false,
		Period:     0,
		PeriodMax:  timeMax,
		TakeEffect: false,
		Callback:   T.Callback}
	return T.Queue[n]
}
